﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Controls;
using System.Windows.Threading;
using NUnit.Framework;
using UnitTestUtils.UI;
using UnitTestUtils.UI.Automation;
using AppToolkit.WPF.UI;

namespace AppToolkit.WPF.Tests.UI
{
    /// <summary>
    /// Attention: Do not set 'RequireSTA' at TestFixture level!
    /// </summary>
    [TestFixture]
    public class ErrorReportDialog_automated
    {
        UIHost _host;
        ErrorReportDialog _target;

        #region Setup / Teardown
        [SetUp]
        public void Setup()
        {
            _target = new ErrorReportDialog();
            _host = UIHost.Create(_target);
        }

        [TearDown]
        public void Dispose()
        {
            _target = null;
            _host = null;
            UnitTestUtils.UI.UITestHelper.CleanupDispatcher();
        } 
        #endregion

        [Test, RequiresSTA]
        public void Pressing_Ignore_Button_sets_IgnoreError_to_true()
        {

            _target.Exception = generateAndSetException();

            _host.Show();

            WindowAutomationPeer windowPeer = new WindowAutomationPeer(_host.Window);

            ButtonAutomationPeer bp = windowPeer.GetProvider<ButtonAutomationPeer>("btnIgnore");
            IInvokeProvider ip = (IInvokeProvider)bp;
            ip.Invoke();
            
            _host.WaitForClose();

            Assert.AreEqual(true, _target.IgnoreError);
        }

        [Test, RequiresSTA]
        public void Pressing_Abort_Button_sets_IgnoreError_to_false()
        {

            _target.Exception = generateAndSetException();

            _host.Show();

            WindowAutomationPeer windowPeer = new WindowAutomationPeer(_host.Window);

            ButtonAutomationPeer bp = windowPeer.GetProvider<ButtonAutomationPeer>("btnIgnore");
            IInvokeProvider ip = (IInvokeProvider)bp;
            ip.Invoke();

            _host.WaitForClose();

            Assert.AreEqual(true, _target.IgnoreError);
        }

        [Test, RequiresSTA]
        public void Navigation_buttons_are_enabled_for_wrapped_exceptions()
        {
            _target.Exception = generateAndSetException();

            _host.Show();
            UIHost.FlushDispatcher();

            WindowAutomationPeer windowPeer = new WindowAutomationPeer(_host.Window);

            TextAutomationPeer tpExceptionType = windowPeer.GetProvider<TextAutomationPeer>("txtExceptionType");
            IValueProvider tp = (IValueProvider)tpExceptionType;
            Assert.AreEqual("InvalidOperationException", tp.Value);

            ButtonAutomationPeer bpInner = windowPeer.GetProvider<ButtonAutomationPeer>("btnNavigateInnerException");
            ButtonAutomationPeer bpOuter = windowPeer.GetProvider<ButtonAutomationPeer>("btnNavigateOuterException");

            Assert.IsTrue(bpInner.IsEnabled());
            Assert.IsFalse(bpOuter.IsEnabled());
            
            // now switch to inner exception
            IInvokeProvider ip = (IInvokeProvider)bpInner;
            bpInner.SetFocus();
            ip.Invoke();
            
            UIHost.FlushDispatcher();

            Assert.AreEqual("ArgumentException", tp.Value);
            Assert.IsTrue(bpOuter.IsEnabled());
            Assert.IsFalse(bpInner.IsEnabled());

            // now switch to outer exception
            ip = (IInvokeProvider)bpOuter;
            bpOuter.SetFocus();
            ip.Invoke();

            UIHost.FlushDispatcher();

            Assert.AreEqual("InvalidOperationException", tp.Value);
            Assert.IsTrue(bpInner.IsEnabled());
            Assert.IsFalse(bpOuter.IsEnabled());

            closeDialog(windowPeer);
        }

        [Test, RequiresSTA]
        public void Copy_to_Clipboard()
        {
            _target.Exception = generateAndSetException();

            _host.Show();
            UIHost.FlushDispatcher();

            WindowAutomationPeer windowPeer = new WindowAutomationPeer(_host.Window);

            ButtonAutomationPeer copyButton = windowPeer.GetProvider<ButtonAutomationPeer>("btnCopyToClipboard");
            Clipboard.Clear();

            // now switch to inner exception
            IInvokeProvider ip = (IInvokeProvider)copyButton;
            copyButton.SetFocus();
            ip.Invoke();

            UIHost.FlushDispatcher();

            string msg = Clipboard.GetText();

            Assert.IsTrue(msg.Contains("ArgumentException"));
            Assert.IsTrue(msg.Contains("InvalidOperationException"));

            closeDialog(windowPeer);
        }

        #region Internals
        public static Exception generateAndSetException()
        {
            string someText = "This is example text to make the exception message longer!";
            try
            {
                try
                {
                    throw new ArgumentException("Inner Exception:\r\n" + someText);
                }
                catch (Exception ex0)
                {
                    throw new InvalidOperationException("Outer Exception\r\n" + someText, ex0);
                }
            }
            catch (Exception ex)
            {
                return ex;
            }
        }
        
        private void closeDialog(WindowAutomationPeer windowPeer)
        {
            ButtonAutomationPeer bp = windowPeer.GetProvider<ButtonAutomationPeer>("btnIgnore");
            IInvokeProvider ip1 = (IInvokeProvider)bp;
            ip1.Invoke();
            _host.WaitForClose();
        }

        class ExceptionHelper
        {
            int _count = 50;

            public int Count
            {
                get { return _count; }
                set { _count = value; }
            }

            public void Call()
            {
                while (_count-- > 0)
                {
                    Call();
                }
                throw new Exception("Some internal exception!");
            }
        } 
        #endregion
    }
}
